package com.sirui.x.learnBoot.global;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Part;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import com.sirui.x.learnBoot.util.JacksonUtil;


@Component
@Aspect
public abstract class AbstractLogAspect {
	
	private static final Logger log = LoggerFactory.getLogger(AbstractLogAspect.class);

    @Pointcut("@annotation(com.sirui.**.LogAno)")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        Signature signature = joinPoint.getSignature();
        String classSimpleName = signature.getDeclaringType().getSimpleName();
        String methodName = signature.getName();

        Object[] args = joinPoint.getArgs();
        if (signature instanceof CodeSignature) {
            CodeSignature methodSignature = (CodeSignature) signature;
            logArgKeyValues(methodSignature, args, classSimpleName, methodName);
        } else {
            logArgValues(args, classSimpleName, methodName);
        }

            Object proceed = joinPoint.proceed();
            log.info("{}.{} resp: {}", classSimpleName, methodName, JacksonUtil.bean2String(proceed));
            return proceed;

    }

    private void logArgKeyValues(CodeSignature signature, Object[] args, String classSimpleName, String methodName) {
        HashMap<String, Object> param = new HashMap<>();
        String[] names = signature.getParameterNames();
        for (int i = 0; i < args.length; i++) {
            if (ifLog(args[i])) {
                param.put(names[i], args[i]);
            }
        }
        log.info("{}.{} req: {}", classSimpleName, methodName, JacksonUtil.bean2String(param));
    }

    private void logArgValues(Object[] args, String classSimpleName, String methodName) {
        List<Object> param = new ArrayList<>(args.length);
        for (int i = 0; i < args.length; i++) {
            if (ifLog(args[i])) {
                param.add(args[i]);
            }
        }
        log.info("{}.{} req: {}", classSimpleName, methodName, JacksonUtil.bean2String(param));
    }

    private boolean ifLog(Object arg) {
        return !(arg instanceof ServletRequest) && !(arg instanceof BindingResult) && !(arg instanceof MultipartFile)
                && !(arg instanceof Part) && !(arg instanceof ServletResponse);
    }
}
